/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package desk;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import hibernate.Product;
import hibernate.ProductCategory;
import hibernate.Request;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Генератор PDF файлов по заданному шаблону
 * @author AGolubinskyy
 */
public class PdfCreator {

    //<editor-fold defaultstate="collapsed" desc="settings">
    private String pathToProperties;
    private BaseFont arial;
    private Font documentTitleFont,
            creationDateFont,
            listTitleFont,
            categoryFont,
            productFont,
            productCountFont,
            userNameFont,
            descriptionFont;
    private Properties props;
    private int[] tableColumnwidths;
    private String documentTitle, listTitle;
    private int documentTitleFontSize,
            creationDateFontSize,
            listTitleFontSize,
            documentTitleAlignment,
            creationDateAlignment,
            listTitleAlignment,
            tableFontSize,
            tableCellsAlignment,
            categoryNameAlignment,
            productNameAlignment,
            productCountAlignment,
            userNameAlignment,
            descriptionAlignment;
    private boolean creationDateRendered,
            listTitleRendered;
    private BaseColor categoryNameBackgroundColor,
            productNameBackgroundColor,
            leftColumnBackgroundColor,
            productCountBackgroundColor,
            userNameBackgroundColor,
            descriptionBackgroundColor,
            categoryNameColor,
            productNameColor,
            productCountColor,
            userNameColor,
            descriptionColor,
            documentTitleColor,
            documentTitleBackgroundColor,
            creationDateColor,
            creationDateBackgroundColor,
            listTitleColor,
            listTitleBackgroundColor;
    //</editor-fold>


    public PdfCreator(String pathToProperties) {
        this.pathToProperties = pathToProperties;
        init();
    }

    /**
     * Сохраняет в файл на диске
     * @param requests - список запросов
     * @param filename - имя файла
     * @throws FileNotFoundException
     * @throws DocumentException
     */
    public void createPdfSaveToFile(List<Request> requests, String filename) throws FileNotFoundException, DocumentException {
        createPdfSaveToStream(requests, new FileOutputStream(filename), true);
    }

    /**
     * Сохраняет в поток
     * @param requests - список запросов
     * @param out - поток
     * @param closeStream - закрывать поток или возвращать открытым
     * @throws DocumentException
     */
    public void createPdfSaveToStream(List<Request> requests, OutputStream out, boolean closeStream) throws DocumentException {
        Document doc = new Document();
        PdfWriter pw = PdfWriter.getInstance(doc, out);
        pw.setCloseStream(closeStream);
        doc.open();

        // adding a title
        
        Chunk documentTitleChunk = new Chunk(documentTitle);
        documentTitleChunk.setBackground(documentTitleBackgroundColor);
        documentTitleChunk.setFont(documentTitleFont);
        Paragraph documentTitleParagraph = new Paragraph(documentTitleChunk);
        //Paragraph documentTitleParagraph = new Paragraph("Сьешь еще этих мягких французских булок, да выпей чаю.");
        documentTitleParagraph.setAlignment(documentTitleAlignment);
        doc.add(documentTitleParagraph);

        // adding creation date if necessary 

        if (creationDateRendered) {
            Chunk creationDateChunk = new Chunk(new Date().toString());
            creationDateChunk.setBackground(creationDateBackgroundColor);
            creationDateChunk.setFont(creationDateFont);
            Paragraph creationDateParagraph = new Paragraph(creationDateChunk);
            creationDateParagraph.setAlignment(creationDateAlignment);
            doc.add(creationDateParagraph);
        }
        
        // adding list title
        
        if (listTitleRendered){
            Chunk listTitleChunk = new Chunk(listTitle);
            listTitleChunk.setBackground(listTitleBackgroundColor);
            listTitleChunk.setFont(listTitleFont);
            Paragraph listTitleParagraph = new Paragraph(listTitleChunk);
            listTitleParagraph.setAlignment(listTitleAlignment);
            listTitleParagraph.setSpacingAfter(7);
            doc.add(listTitleParagraph);
        }
        
        //building a table
        
        PdfPTable table = new PdfPTable(4);
        table.setWidths(tableColumnwidths);
        table.getDefaultCell().setHorizontalAlignment(Element.ALIGN_MIDDLE);
        table.setSplitRows(true);
        table.setSplitLate(true);
        
        for (ProductCategory pc : getCategories(requests)) {
            PdfPCell categoryCell = getTableCell(
                    4, 
                    categoryNameBackgroundColor, 
                    pc.getDescription(), 
                    categoryFont, 
                    categoryNameAlignment, 
                    Element.ALIGN_MIDDLE);
            table.addCell(categoryCell);
            
            for (Product product : getProductsInCategory(pc, requests)) {
                
                PdfPCell productColCell = new PdfPCell();
                productColCell.setRowspan(getRequestsForProduct(product, requests).size() + 1);
                productColCell.setBackgroundColor(leftColumnBackgroundColor);
                table.addCell(productColCell);
                
                PdfPCell productCell = getTableCell(
                        2, 
                        productNameBackgroundColor, 
                        product.getDescription(), 
                        productFont, 
                        productNameAlignment, 
                        Element.ALIGN_MIDDLE);
                table.addCell(productCell);
                
                PdfPCell productCountCell = getTableCell(
                        1, 
                        productCountBackgroundColor, 
                        Integer.toString(getRequestsForProduct(product, requests).size()), 
                        productCountFont, 
                        productCountAlignment, 
                        Element.ALIGN_MIDDLE);
                table.addCell(productCountCell);
                
                for (Request r : getRequestsForProduct(product, requests)) {
                    
                    PdfPCell userNameCell = getTableCell(
                        1, 
                        userNameBackgroundColor, 
                        r.getUser().getFirstName() + " " + r.getUser().getLastName(), 
                        userNameFont, 
                        userNameAlignment, 
                        Element.ALIGN_MIDDLE);
                    table.addCell(userNameCell);
                    
                    PdfPCell descriptionCell =  getTableCell(
                        1, 
                        descriptionBackgroundColor, 
                        r.getDescription(), 
                        descriptionFont, 
                        descriptionAlignment, 
                        Element.ALIGN_MIDDLE);
                    table.addCell(descriptionCell);
                    
                    table.addCell(new PdfPCell());
                    
                }
                
            }
        }
        doc.add(table);
        doc.close();
    }

    /**
     * Инициализация настроек и параметров шаблона
     */
    public final void init() {
        //<editor-fold defaultstate="collapsed" desc="initialisation">
        props = new Properties();
        try {
            //String s = this.getClass().getResource(pathToProperties).toString();
            //props.load(new FileInputStream(pathToProperties));
            props.load(this.getClass().getResourceAsStream(pathToProperties));
            
        } catch (FileNotFoundException ex) {
            Logger.getLogger(PdfCreator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(PdfCreator.class.getName()).log(Level.SEVERE, null, ex);
        }
        tableColumnwidths = getWidths(props.getProperty("tableColumnWidths", "1,5,10,2"));
        documentTitle = props.getProperty("documentTitle");
        documentTitleFontSize = Integer.parseInt(props.getProperty("documentTitleFontSize"));
        documentTitleAlignment = getAlignment(props.getProperty("documentTitleAlignment"));
        creationDateAlignment = getAlignment(props.getProperty("creationDateAlignment"));
        creationDateFontSize = Integer.parseInt(props.getProperty("creationDateFontSize"));
        creationDateRendered = getBoolean(props.getProperty("creationDateRendered"));
        listTitle = props.getProperty("listTitle");
        listTitleFontSize = Integer.parseInt(props.getProperty("listTitleFontSize"));
        listTitleAlignment = getAlignment(props.getProperty("listTitleAlignment"));
        listTitleRendered = getBoolean(props.getProperty("listTitleRendered"));
        
        tableFontSize = Integer.parseInt(props.getProperty("tableFontSize"));
        tableCellsAlignment = getAlignment(props.getProperty("tableCellsAlignment"));
        
        categoryNameAlignment = getAlignment(props.getProperty("categoryNameAlignment"));
        productNameAlignment = getAlignment(props.getProperty("productNameAlignment"));
        productCountAlignment = getAlignment(props.getProperty("productCountAlignment"));
        userNameAlignment = getAlignment(props.getProperty("userNameAlignment"));
        descriptionAlignment = getAlignment(props.getProperty("descriptionAlignment"));
        
        categoryNameBackgroundColor = getColor(props.getProperty("categoryNameBackgroundColor"));
        productNameBackgroundColor = getColor(props.getProperty("productNameBackgroundColor"));
        leftColumnBackgroundColor = getColor(props.getProperty("leftColumnBackgroundColor"));
        productCountBackgroundColor = getColor(props.getProperty("productCountBackgroundColor"));
        userNameBackgroundColor = getColor(props.getProperty("userNameBackgroundColor"));
        descriptionBackgroundColor = getColor(props.getProperty("descriptionBackgroundColor"));
        
        categoryNameColor = getColor(props.getProperty("categoryNameColor"));
        productNameColor = getColor(props.getProperty("productNameColor"));
        productCountColor = getColor(props.getProperty("productCountColor"));
        userNameColor = getColor(props.getProperty("userNameColor"));
        descriptionColor = getColor(props.getProperty("descriptionColor"));
        
        documentTitleColor = getColor(props.getProperty("documentTitleColor"));
        documentTitleBackgroundColor = getColor(props.getProperty("documentTitleBackgroundColor"));
        creationDateColor = getColor(props.getProperty("creationDateColor"));
        creationDateBackgroundColor = getColor(props.getProperty("creationDateBackgroundColor"));
        
        listTitleColor = getColor(props.getProperty("listTitleColor"));
        listTitleBackgroundColor = getColor(props.getProperty("listTitleBackgroundColor"));
        try {
            arial = BaseFont.createFont(this.getClass().getResource("arial.ttf").toString(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        } catch (DocumentException ex) {
            Logger.getLogger(PdfCreator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(PdfCreator.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        documentTitleFont = new Font(arial, documentTitleFontSize);
        documentTitleFont.setColor(documentTitleColor);
        
        creationDateFont = new Font(arial, creationDateFontSize);
        creationDateFont.setColor(creationDateColor);
        
        listTitleFont = new Font(arial, listTitleFontSize);
        listTitleFont.setColor(listTitleColor);
        
        categoryFont = new Font(arial, tableFontSize);
        categoryFont.setColor(categoryNameColor);
        
        productFont = new Font(arial, tableFontSize);
        productFont.setColor(productNameColor);
        
        productCountFont = new Font(arial, tableFontSize);
        productCountFont.setColor(productCountColor);
        
        userNameFont = new Font(arial, tableFontSize);
        userNameFont.setColor(userNameColor);
        
        descriptionFont = new Font(arial, tableFontSize);
        descriptionFont.setColor(descriptionColor);
        //</editor-fold>
    }

    private static PdfPCell getTableCell(
            int colspan,
            BaseColor backgroundColor,
            String text,
            Font font,
            int horisontalAlignment,
            int verticalAlignment) {
        PdfPCell cell = new PdfPCell();
        cell.setColspan(colspan);
        cell.setBackgroundColor(backgroundColor);
        cell.setPaddingBottom(4);
        Chunk categoryNameChunk = new Chunk(text);
        categoryNameChunk.setFont(font);
        Paragraph paragraph = new Paragraph(categoryNameChunk);
        paragraph.setAlignment(horisontalAlignment);
        paragraph.setSpacingBefore(0);
        paragraph.setLeading(8, 0.3f);
        cell.setHorizontalAlignment(horisontalAlignment);
        cell.addElement(paragraph);
        return cell;
    }

    private static int[] getWidths(String widths) {
        int[] wi = new int[4];
        String[] temp = widths.split(",");
        for (int i = 0; i < wi.length; i++) {
            wi[i] = Integer.parseInt(temp[i]);
        }
        return wi;
    }

    private static int getAlignment(String property) {
        if (property.toLowerCase().equals("left")) {
            return Element.ALIGN_LEFT;
        }
        if (property.toLowerCase().equals("right")) {
            return Element.ALIGN_RIGHT;
        }
        if (property.toLowerCase().equals("center")) {
            return Element.ALIGN_CENTER;
        }
        if (property.toLowerCase().equals("justify")) {
            return Element.ALIGN_JUSTIFIED;
        }
        if (property.toLowerCase().equals("top")) {
            return Element.ALIGN_TOP;
        }
        if (property.toLowerCase().equals("bottom")) {
            return Element.ALIGN_BOTTOM;
        }
        if (property.toLowerCase().equals("middle")) {
            return Element.ALIGN_MIDDLE;
        }
        return Element.ALIGN_LEFT;
    }

    private static boolean getBoolean(String property) {
        if (property.equals("0")) {
            return false;
        } else {
            return true;
        }
    }

    private static BaseColor getColor(String property) {
        if (property.split(",").length > 1) {
            String[] cols = property.split(",");
            return new BaseColor(Integer.parseInt(cols[0]), Integer.parseInt(cols[1]), Integer.parseInt(cols[2]));
        }

        if (property.toLowerCase().equals("black")) {
            return BaseColor.BLACK;
        }
        if (property.toLowerCase().equals("blue")) {
            return BaseColor.BLUE;
        }
        if (property.toLowerCase().equals("cyan")) {
            return BaseColor.CYAN;
        }
        if (property.toLowerCase().equals("dark_gray")) {
            return BaseColor.DARK_GRAY;
        }
        if (property.toLowerCase().equals("gray")) {
            return BaseColor.GRAY;
        }
        if (property.toLowerCase().equals("green")) {
            return BaseColor.GREEN;
        }
        if (property.toLowerCase().equals("light_gray")) {
            return BaseColor.LIGHT_GRAY;
        }
        if (property.toLowerCase().equals("magenta")) {
            return BaseColor.MAGENTA;
        }
        if (property.toLowerCase().equals("orange")) {
            return BaseColor.ORANGE;
        }
        if (property.toLowerCase().equals("pink")) {
            return BaseColor.PINK;
        }
        if (property.toLowerCase().equals("red")) {
            return BaseColor.RED;
        }
        if (property.toLowerCase().equals("white")) {
            return BaseColor.WHITE;
        }
        if (property.toLowerCase().equals("yellow")) {
            return BaseColor.YELLOW;
        }
        return BaseColor.BLACK;
    }

    private static List<ProductCategory> getCategories(List<Request> requests) {
        ArrayList<ProductCategory> cats = new ArrayList<ProductCategory>();
        for (Request r : requests) {
            if (!cats.contains(r.getProduct().getProdCategory())) {
                cats.add(r.getProduct().getProdCategory());
            }
        }
        return cats;
    }

    private static List<Product> getProductsInCategory(ProductCategory pc, List<Request> requests) {
        ArrayList<Product> prods = new ArrayList<Product>();
        for (Request r : requests) {
            if (r.getProduct().getProdCategory().getId() == pc.getId()
                    && !prods.contains(r.getProduct())) {
                prods.add(r.getProduct());
            }
        }
        return prods;

    }

    private static List<Request> getRequestsForProduct(Product product, List<Request> requests) {
        ArrayList<Request> req = new ArrayList<Request>();
        for (Request r : requests) {
            if (r.getProduct().getId() == product.getId()) {
                req.add(r);
            }
        }
        return req;
    }
}
